package fabrik;

import java.util.ArrayList;

import java.util.Collections;

import readin.ReadIn;


/**
 * This class represents the project, it contains lists of all the processes and
 * relations between the processes.
 * 
 * @author Janet
 * @version 1.0
 */
public class Project {
	// the strings which we will use later for seearching
	private static final String PROJECTBEGIN = "Projektbeginn";
	private static final String PROJECTEND = "Projektende";
	// name of the project
	private String name;
	// int values for projectstart and end
	private int projectStart;
	private int projectEnd;
	// the list which conttain the processes and relations
	private ArrayList<Process> processList = new ArrayList<Process>();;
	private ArrayList<Relations> relationList = new ArrayList<Relations>();
	// the process start and end
	private Process start;
	private Process end;

	/**
	 * The constructor of this class.
	 * 
	 * @param inputFilePath
	 *            , the path to the file to read in.
	 */
	public Project(String inputFilePath) {
		// initializes the project
		ReadIn.initializeProjectWithFile(inputFilePath, this);
		// sets the relations
		setRelation();
		// sets the start process with the name projectbegin
		start = getProcessByName(PROJECTBEGIN);
		// sets the end process with the name projectend
		end = getProcessByName(PROJECTEND);
		// sets the faz and fez values for projectstart and end
		setProjectStartEnd();
	}

	/**
	 * The second constructor if its the case, that the projectstart and end
	 * don't contain the word "Projektbeginn" and "Projektende", we take the
	 * first and last tasks name and set it to start and end.
	 * 
	 * @param inputFilePath
	 *            , path of the file
	 * @param startProcessName
	 *            , the name of the start process
	 * @param endProcessName
	 *            , the name of the end process
	 */
	public Project(String inputFilePath, String startProcessName,
			String endProcessName) {
		ReadIn.initializeProjectWithFile(inputFilePath, this);
		// sets the relations
		setRelation();
		// sets the start process with the name startProcessName
		start = getProcessByName(startProcessName);
		// sets the end process with the name endProcessName
		end = getProcessByName(endProcessName);
		// sets the faz and fez values for projectstart and end
		setProjectStartEnd();
	}

	/**
	 * This method sets the relations of the processes.
	 */
	public void setRelation() {
		// goes through the relation list and sets the relation for the
		// predecessors and successors
		for (int i = 0; i < relationList.size(); i++) {
			Relations relation = relationList.get(i);
			relation.getPre().getSuccessorRelListe().add(relation);
			relation.getSuccessor().getPreRelListe().add(relation);
		}
	}

	/**
	 * This method returns the list of relations.
	 * 
	 * @return relation list
	 */
	public ArrayList<Relations> getRelationList() {
		return relationList;
	}

	/**
	 * getter for the name.
	 * 
	 * @return name or project
	 */
	public String getName() {
		return name;
	}

	/**
	 * setter of the project name.
	 * 
	 * @param name
	 *            of the project
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * getter for projectstart.
	 * 
	 * @return projectstart, the start of the project
	 */
	public int getProjectStart() {
		return projectStart;
	}

	/**
	 * getter for projectend.
	 * 
	 * @return projectEnd, the end of the project
	 */
	public int getProjectEnd() {
		return projectEnd;
	}

	/**
	 * sets the project start of the project.
	 * 
	 * @param projectStart
	 *            , start of the project
	 */
	public void setProjectStart(int projectStart) {
		this.projectStart = projectStart;
	}

	/**
	 * sets the project end of the project.
	 * 
	 * @param projectEnd
	 *            , end of the project
	 */
	public void setProjectEnd(int projectEnd) {
		this.projectEnd = projectEnd;
	}

	/**
	 * returns the list of the processes.
	 * 
	 * @return processList, the list of processes
	 */
	public ArrayList<Process> getProcessList() {
		return processList;
	}

	/**
	 * sets the process list.
	 * 
	 * @param processList
	 *            , list of all the processes
	 */
	public void setProcessList(ArrayList<Process> processList) {
		this.processList = processList;
	}

	/**
	 * sets relation list.
	 * 
	 * @param relationList
	 *            , list of the relations
	 */
	public void setRelationList(ArrayList<Relations> relationList) {
		this.relationList = relationList;
	}

	/**
	 * This method finds the process with the searched name.
	 * 
	 * @param name
	 *            , we are searching for in the process list
	 * @return process if found, else null
	 */
	public Process getProcessByName(String name) {

		for (Process process : processList) {
			// goes through the processList and compares every name with the
			// searched one
			if (process.getName().equalsIgnoreCase(name)) {
				return process;
			}
		}
		return null;
	}

	/**
	 * This method looks for a process with the searched ID.
	 * 
	 * @param id
	 *            , which we are looking for
	 * @return process with the searched ID,else null
	 */
	public Process getProcessById(int id) {
		// goes through the processList and compares every ID with the searched
		// one
		for (Process process : processList) {
			if (process.getID() == id)
				return process;
		}
		return null;
	}

	/**
	 * It sets the FAZ and FEZ values of the projectstart and end.
	 * 
	 */
	public void setProjectStartEnd() {
		// the projectbegin and set its FAZ and FEZ values
		start.setFAZ(getProjectStart());
		start.setFEZ(getProjectStart() + start.getPeriod());
		// set the SAZ and SEZ values of the projectend
		end.setSEZ(getProjectEnd());
		end.setSAZ(getProjectEnd() - end.getPeriod());

	}

	/**
	 * This method sorts die List of relations by the ID of its
	 * predecessors,rising.
	 */
	public void sortRelationListByPrecessor() {
		Collections.sort(relationList);
	}

	/**
	 * The forward calculation. It leads to the forward Calculation in class
	 * Process
	 */
	public void forwardCalculation() {
		end.getFEZ();
	}

	/**
	 * The forward calculation. It leads to the backward Calculation in class
	 * Process
	 */
	public void backwardCalculation() {
		start.getSEZ();
	}

	/**
	 * This method calculates the total puffer.
	 * 
	 */
	public void setTotalPuffer() {
		// goes through the list and calculates each total puffer by the
		// difference of
		// its FAZ and SAZ
		for (int i = 0; i < processList.size(); i++) {
			Process pre = processList.get(i);
			pre.setTotalPuffer(pre.getSAZ() - pre.getFAZ());
		}
	}

	/**
	 * This method calculates the free puffer.
	 * 
	 */
	public void calculateFreePuffer() {
		// goes through the list
		for (int i = 0; i < processList.size(); i++) {
			ArrayList<Integer> possible = new ArrayList<Integer>();
			// goes through the list of successor of the process
			for (Relations rel : processList.get(i).getSuccessorRelListe()) {
				Process successor = rel.getSuccessor();
				// check the relation and calculate the free puffer and than add
				// it to the list possible
				// later on we will look for the min in the list
				switch (rel.getType()) {
				case AA:
					possible.add(successor.getFAZ()
							- processList.get(i).getFAZ());
					break;
				case EA:
					possible.add(successor.getFAZ()
							- processList.get(i).getFEZ());
					break;
				case AE:
					possible.add(successor.getFEZ()
							- processList.get(i).getFAZ());
					break;
				case EE:
					possible.add(successor.getFEZ()
							- processList.get(i).getFEZ());
					break;
					default: System.out.println("Error!Invalid relation type.");
				}
			}
			// if we are at the end of the list, the size of the successors is
			// zero
			// so set its free puffer to zero
			if (possible.size() == 0) {
				processList.get(i).setFreePuffer(0);
			} else
				// else we calculate the minimumFAZ/FEZ of the successor and add
				// it to endMin
				processList.get(i).setFreePuffer(Collections.min(possible));
		}
	}

	/**
	 * String to string method, returns project with its contents.
	 * @return the start,end name and list of the project
	 */
	@Override
	public String toString() {
		return "project" + ";" + projectStart + ";" + projectEnd + ";" + name
				+ "\n" + processList + relationList;
	}

	/**
	 * This method prints out the whole project,including tasks,aobs and all the
	 * time values.
	 */
	public void print() {
		System.out.print("project" + ";" + getProjectStart() + ";"
				+ getProjectEnd() + ";" + getName() + "\n");
		for (int i = 0; i < getProcessList().size(); i++) {
			Process process = getProcessList().get(i);
			System.out.print("task" + ";" + process.getID() + ";"
					+ process.getPeriod() + ";" + process.getName() + "\n");
			System.out.print("early" + ";" + process.getID() + ";"
					+ process.getFAZ() + ";" + process.getFEZ() + "\n");
			System.out.print("late" + ";" + process.getID() + ";"
					+ process.getSAZ() + ";" + process.getSEZ() + "\n");
			System.out.print("float" + ";" + process.getID() + ";"
					+ process.getTotalPuffer() + ";" + process.getFreePuffer()
					+ "\n");
			for (Relations rel : process.getSuccessorRelListe()) {
				System.out.print("aob" + ";" + rel.getPre().getID() + ";"
						+ rel.getSuccessor().getID() + ";" + rel.getType()
						+ "\n");
			}
		}
	}
}
